/*
* @Author: baidwwy
* @Date:   2019-04-08 09:42:13
* @Last Modified by:   baidwwy
* @Last Modified time: 2020-05-17 01:18:35
*/
#include "gge.h"

static int LUA_CreateRect(lua_State *L){
	SDL_Rect *rect;
	int x = (int)luaL_optinteger(L, 1,0);
	int y = (int)luaL_optinteger(L, 2,0);
	int w = (int)luaL_optinteger(L, 3,0);
	int h = (int)luaL_optinteger(L, 4,0);
	rect = (SDL_Rect*)lua_newuserdata(L, sizeof (SDL_Rect));
	rect->x = x;
	rect->y = y;
	rect->w = w;
	rect->h = h;
	luaL_setmetatable(L, "SDL_Rect");
	return 1;
}

static int LUA_CreateFRect(lua_State *L){
	SDL_FRect *rect;
	float x = (float)luaL_optnumber(L, 1,0);
	float y = (float)luaL_optnumber(L, 2,0);
	float w = (float)luaL_optnumber(L, 3,0);
	float h = (float)luaL_optnumber(L, 4,0);
	rect = (SDL_FRect*)lua_newuserdata(L, sizeof (SDL_FRect));
	rect->x = x;
	rect->y = y;
	rect->w = w;
	rect->h = h;
	luaL_setmetatable(L, "SDL_FRect");
	return 1;
}

static int LUA_SetRect(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");

	rect->x = (int)luaL_optinteger(L,2,rect->x);
	rect->y = (int)luaL_optinteger(L,3,rect->y);
	rect->w = (int)luaL_optinteger(L,4,rect->w);
	rect->h = (int)luaL_optinteger(L,5,rect->h);
	return 0;
}

static int LUA_GetRect(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	lua_pushinteger(L,rect->x);
	lua_pushinteger(L,rect->y);
	lua_pushinteger(L,rect->w);
	lua_pushinteger(L,rect->h);
	return 4;
}

static int LUA_SetRectXY(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	rect->x = (int)luaL_optinteger(L,2,rect->x);
	rect->y = (int)luaL_optinteger(L,3,rect->y);
	return 0;
}

static int LUA_GetRectXY(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	lua_pushinteger(L,rect->x);
	lua_pushinteger(L,rect->y);
	return 2;
}

static int LUA_SetRectWH(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	rect->w = (int)luaL_optinteger(L,2,rect->w);
	rect->h = (int)luaL_optinteger(L,3,rect->h);
	return 0;
}

static int LUA_GetRectWH(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	lua_pushinteger(L,rect->w);
	lua_pushinteger(L,rect->h);
	return 2;
}

static int LUA_PointInRect(lua_State *L)
{
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	SDL_Point p;
	p.x = luaL_checkinteger(L,2);
	p.y = luaL_checkinteger(L,3);
	lua_pushboolean(L,SDL_PointInRect(&p, rect));
	return 1;
}

static int LUA_RectEmpty(lua_State *L)
{
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	lua_pushboolean(L,SDL_RectEmpty(rect));
	return 1;
}

static int LUA_RectEquals(lua_State *L)
{
	SDL_Rect * A = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	SDL_Rect * B = (SDL_Rect*)luaL_checkudata(L, 2, "SDL_Rect");
	lua_pushboolean(L,SDL_RectEquals(A, B));
	return 1;
}

static int LUA_HasIntersection(lua_State *L)
{
	SDL_Rect * A = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	SDL_Rect * B = (SDL_Rect*)luaL_checkudata(L, 2, "SDL_Rect");
	lua_pushboolean(L,SDL_HasIntersection(A,B));
	return 1;
}

static int LUA_IntersectRect(lua_State *L)
{
	SDL_Rect * A = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	SDL_Rect * B = (SDL_Rect*)luaL_checkudata(L, 2, "SDL_Rect");

	SDL_Rect *result=(SDL_Rect*)lua_newuserdata(L, sizeof (SDL_Rect));
	luaL_setmetatable(L, "SDL_Rect");
	SDL_IntersectRect(A,B, result);
	return 1;
}

static int LUA_UnionRect(lua_State *L)
{
	SDL_Rect * A = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	SDL_Rect * B = (SDL_Rect*)luaL_checkudata(L, 2, "SDL_Rect");
	SDL_Rect *result = (SDL_Rect*)lua_newuserdata(L, sizeof (SDL_Rect));

	SDL_UnionRect(A, B, result);
	luaL_setmetatable(L, "SDL_Rect");
	return 1;
}

static int LUA_IntersectRectAndLine(lua_State *L)
{
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	int x1, y1, x2, y2;

	x1 = (int)luaL_checkinteger(L, 2);
	y1 = (int)luaL_checkinteger(L, 3);
	x2 = (int)luaL_checkinteger(L, 4);
	y2 = (int)luaL_checkinteger(L, 5);

	if(SDL_IntersectRectAndLine(rect, &x1, &y1, &x2, &y2)==SDL_TRUE){
		lua_pushinteger(L,x1);
		lua_pushinteger(L,y1);
		lua_pushinteger(L,x2);
		lua_pushinteger(L,y2);
		return 4;
	}
	return 0;
}

static int LUA_RectIndex(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	const char* key = lua_tostring(L,2);
	switch(key[0]){
	case 'x':
		lua_pushinteger(L,rect->x);break;
	case 'y':
		lua_pushinteger(L,rect->y);break;
	case 'w':
		lua_pushinteger(L,rect->w);break;
	case 'h':
		lua_pushinteger(L,rect->h);break;
	default:
		luaL_getmetatable(L,"SDL_Rect");
		lua_getfield(L,-1,key);
		lua_remove(L, -2);
	}
	return 1;
}

static int LUA_RectNewIndex(lua_State *L){
	SDL_Rect * rect = (SDL_Rect*)luaL_checkudata(L, 1, "SDL_Rect");
	const char* key = lua_tostring(L,2);
	int value = (int)luaL_checkinteger(L,3);

	switch(key[0]){
	case 'x':
		rect->x = value;break;
	case 'y':
		rect->y = value;break;
	case 'w':
		rect->w = value;break;
	case 'h':
		rect->h = value;break;
	}
	return 0;
}

static int LUA_FRectIndex(lua_State *L){
	SDL_FRect * rect = (SDL_FRect*)luaL_checkudata(L, 1, "SDL_Rect");
	const char* key = lua_tostring(L,2);
	switch(key[0]){
	case 'x':
		lua_pushnumber(L,rect->x);break;
	case 'y':
		lua_pushnumber(L,rect->y);break;
	case 'w':
		lua_pushnumber(L,rect->w);break;
	case 'h':
		lua_pushnumber(L,rect->h);break;
	default:
		luaL_getmetatable(L,"SDL_Rect");
		lua_getfield(L,-1,key);
		lua_remove(L, -2);
	}
	return 1;
}

static int LUA_FRectNewIndex(lua_State *L){
	SDL_FRect * rect = (SDL_FRect*)luaL_checkudata(L, 1, "SDL_Rect");
	const char* key = lua_tostring(L,2);
	float value = (float)luaL_checknumber(L,3);

	switch(key[0]){
	case 'x':
		rect->x = value;break;
	case 'y':
		rect->y = value;break;
	case 'w':
		rect->w = value;break;
	case 'h':
		rect->h = value;break;
	}
	return 0;
}

static const luaL_Reg SDL_Rect_Meta[] = {
	{"SetRect"				, LUA_SetRect}        ,
	{"GetRect"				, LUA_GetRect}        ,
	{"SetRectXY"			, LUA_SetRectXY}        ,
	{"SetRectWH"			, LUA_SetRectWH}        ,
	{"GetRectXY"			, LUA_GetRectXY}        ,
	{"GetRectWH"			, LUA_GetRectWH}        ,
	//{"EnclosePoints"        , LUA_EnclosePoints}        ,
	{"HasIntersection"      , LUA_HasIntersection}      ,
	{"IntersectRect"        , LUA_IntersectRect}        ,
	{"IntersectRectAndLine" , LUA_IntersectRectAndLine} ,
	{"PointInRect"          , LUA_PointInRect}          ,
	{"RectEmpty"            , LUA_RectEmpty}            ,
	{"UnionRect"            , LUA_UnionRect}            ,

	{ NULL,	NULL}
};

static const luaL_Reg SDL_Meta[] = {
	{"CreateRect" , LUA_CreateRect} ,
	{"CreateFRect" , LUA_CreateFRect} ,
	{ NULL,	NULL}
};

void OPEN_Rect(lua_State *L)
{
	luaL_newmetatable(L,"SDL_Rect");
	luaL_setfuncs(L,SDL_Rect_Meta,0);
	lua_pushcfunction(L,LUA_RectIndex);
	lua_setfield(L, -2, "__index");
	lua_pushcfunction(L,LUA_RectNewIndex);
	lua_setfield(L, -2, "__newindex");
	lua_pop(L, 1);

	luaL_setfuncs(L,SDL_Meta,0);
}